package minimips

import (
	"fmt"
	"dumpwave"
)

func fetch(
	branch_decision	chan uint,
	decode_instr	chan uint,
	imem_address	chan uint,
	imem_data	chan uint) {

	var instr uint
	var PC, branch_d, branch_offset uint = 0, 0, 0
	for {
		fmt.Println("[fetch] PC --> IMEM:",PC)
		
		dumpwave.Wave(1,"imem_addressRA")
		dumpwave.Wave(int(PC),"imem_address")
		imem_address <- PC
		dumpwave.Wave(0,"imem_addressRA")
		
		instr =<- imem_data
		fmt.Printf("[fetch] INSTR <-- IMEM: 0x%x\n", instr)

		switch ((instr & 0xFC000000)>>26) { //OP code
			case 0x4: //beq
				fmt.Println("[fetch] INSTR --> DECODE")
				dumpwave.Wave(1,"decode_instrRA")
				dumpwave.Wave(int(instr),"decode_instr")
				decode_instr <- instr
				dumpwave.Wave(0,"decode_instrRA")
				branch_d =<- branch_decision
				fmt.Println("[fetch] BRANCH_D <-- EXECUTE:",branch_d)
				if branch_d == 1 {
					for i:=uint(1); i<17; i++ {
						branch_offset = branch_offset | (instr & 0x8000)<<i
					}
					branch_offset = branch_offset | (instr & 0xFFFF)
					fmt.Println("[fetch] branch_offset:", int(branch_offset))
					fmt.Println("[fetch] PC:", int(PC))
					PC = uint(int(PC+1) + int(branch_offset))
					fmt.Println("[fetch] PC:", int(PC))
				} else {
						PC++
						fmt.Println("[fetch] PC =", PC)
				}
			case 0x6: //j
				fmt.Println("[fetch] Operação JUMP")
				PC = (PC & 0xFC000000) | (instr & 0x3FFFFFF)
				fmt.Println("[fetch] PC + branch_offset:", PC)
			default:
				fmt.Printf("[fetch] INSTR --> DECODE: 0x%x\n", instr)
				dumpwave.Wave(1,"decode_instrRA")
				dumpwave.Wave(int(instr),"decode_instr")
				decode_instr <- instr
				dumpwave.Wave(0,"decode_instrRA")
				PC++
		}
	}
}
